package com.java.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.List;

public class DBUtil {
    //1.定义变量
    protected Connection connection;
    protected PreparedStatement pps;
    protected ResultSet rs;
    protected int count;//存储受影响的行数

    // 缓存方法集合
    private static final Map<Class<?>, List<Method>> methodMapping = new HashMap<>();


    //3.获得链接
    protected Connection getConnection() throws SQLException {
        return connection = DruidUtil.getConnection();
    }

    //4.得到预状态通道
    protected PreparedStatement pps(String sql, int autoGeneratedKeys) throws SQLException {
        return pps = getConnection().prepareStatement(sql, autoGeneratedKeys);
    }

    //4.得到预状态通道
    protected PreparedStatement pps(String sql) throws SQLException {
        return pps(sql, Statement.NO_GENERATED_KEYS);
    }

    //5.绑定参数  List保存的是给占位符所赋的值
    protected void param(PreparedStatement pps, List<Object> list) throws SQLException {
        if (pps == null) {
            pps = this.pps;
        }
        if (pps != null && list != null && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                pps.setObject(i + 1, list.get(i));
            }
        }
    }

    //6.执行操作(增删改+查询)
    protected int update(PreparedStatement pps, List<Object> list) throws SQLException {
        param(pps, list);
        return count = pps.executeUpdate();
    }

    //6.执行操作(增删改+查询)
    protected int update(PreparedStatement pps, Object oneParam) throws SQLException {
        pps.setObject(1, oneParam);
        return count = pps.executeUpdate();
    }

    //7.查询
    protected ResultSet query(PreparedStatement pps, List<Object> list) throws SQLException {
        param(pps, list);
        return rs = pps.executeQuery();
    }
    //7.查询
    protected ResultSet query(PreparedStatement pps, Object param) throws SQLException {
        pps.setObject(1, param);
        return rs = pps.executeQuery();
    }

    //8.关闭资源
    protected void closeAll() {
        DruidUtil.close(connection, pps, rs);
        connection = null;
        pps = null;
        rs = null;
    }

    // 反射给实体类集合赋值
    protected <T> List<T> setAll(Class<T> cla) throws Exception {

        if (rs == null || cla == null)
            return null;

        final Constructor<T> claConstructor = cla.getConstructor();
        T t = setOne(cla);
        if (t == null)
            return null;
        final List<T> result = new ArrayList<>();
        result.add(t);

        final List<Method> sortedMethodsList = methodMapping.get(cla);
        while (rs.next()) {
            t = claConstructor.newInstance();
            int i = 1;
            for (Method method : sortedMethodsList) {
                if (method != null)
                    method.invoke(t, rs.getObject(i++));
                else
                    i++;
            }
            result.add(t);
        }
        return result;
    }

    // 反射给一个实体类赋值
    protected <T> T setOne(Class<T> cla) throws Exception {
        final Constructor<T> claConstructor = cla.getConstructor();
        final Method[] methods = claConstructor.newInstance().getClass().getMethods();
        final List<Method> sortedMethodsList;
        if (rs.next()) {
            final ResultSetMetaData metaData = rs.getMetaData();
            final int columnCount = metaData.getColumnCount();
            final T t = claConstructor.newInstance();

            if (!methodMapping.containsKey(cla)) {
                sortedMethodsList = new ArrayList<>();
                int sizeOfSortedMethodsList = 0;
                // 遍历所有列，获取字符串  `“set” + 列名`
                for (int iColumnIndex = 1; iColumnIndex <= columnCount; iColumnIndex++) {
                    final String setColumnName = "set" + metaData.getColumnName(iColumnIndex);
                    // 遍历所有方法，将方法名与 `“set” + 列名` 对比
                    for (Method method : methods) {
                        if (method.getName().equalsIgnoreCase(setColumnName)) {
                            // 方法名与 `“set” + 列名` 相同（忽略大小写），调用该方法
                            method.invoke(t, rs.getObject(iColumnIndex));
                            // 将该方法存到集合中
                            sortedMethodsList.add(method);
                            break;
                        }
                    }
                    // 如果集合的尺寸没有变化， 则说明没有方法与 `“set” + 列名` 相同
                    if (sortedMethodsList.size() == sizeOfSortedMethodsList) {
                        // 添加一个空指针 以便下次调用方法时可以跳过这列
                        sortedMethodsList.add(null);
                    } else {
                        sizeOfSortedMethodsList = sortedMethodsList.size();
                    }
                }
                methodMapping.put(cla, sortedMethodsList);
            } else {
                sortedMethodsList = methodMapping.get(cla);
                int i = 1;
                try {
                    for (Method method : sortedMethodsList) {
                        // 如果是一个空指针则跳过这列
                        if (method != null)
                            method.invoke(t, rs.getObject(i++));
                        else
                            i++;
                    }
                } catch (IllegalArgumentException e) {
                    // 方法集合与列不对应，移除方法集合
                    methodMapping.remove(cla);
                    // 重新配置方法集合
                    return setOne(cla);
                }
            }

            return t;
        }
        return null;
    }

    // 获得一个数
    protected Integer getCount() throws SQLException {
        if (rs.next())
            return rs.getInt(1);
        return null;
    }

}
